package dataStructure.graph;

import java.util.LinkedList;
import java.util.Queue;

public class DFSAndBFS {
    /**
     * BFS 只能遍历连通图
     *
     * @param graph 图
     * @param i     起始访问下标
     * @param flag  访问标记数组
     * @param queue 访问队列
     */
    private static void BFS(GraphMatrix graph, int i, boolean[] flag, Queue<Integer> queue) {
        if (!flag[i]) {
            flag[i] = true;
            System.out.print(graph.vertexList.get(i) + " ");
            queue.offer(i);
            while (!queue.isEmpty()) {
                //取出队列中结点
                int k = queue.poll();
                for (int j = 0; j < graph.getVertexNum(); j++) {
                    //访问与k结点相连的所有结点，如果没有被访问，标记结点
                    if (graph.edges[k][j] == 1 && !flag[j]) {
                        flag[j] = true;
                        System.out.print(graph.vertexList.get(j) + " ");
                        //结点插入队列
                        queue.offer(j);
                    }
                }
            }
        }
    }

    /**
     * BFS 可以遍历非连通图
     *
     * @param graph 图
     */
    static void BFSTraverse(GraphMatrix graph) {
        boolean[] flag = new boolean[graph.getVertexNum()];
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < graph.getVertexNum(); i++) {
            BFS(graph, i, flag, queue);
        }
    }

    /**
     * DFS 只能遍历连通图
     *
     * @param graph 图
     * @param i     起始访问下标
     * @param flag  访问标记数组
     */
    private static void DFS(GraphMatrix graph, int i, boolean[] flag) {
        flag[i] = true;// 第i个顶点被访问
        System.out.print(graph.vertexList.get(i) + " ");
        for (int j = 0; j < graph.getVertexNum(); j++) {
            if (!flag[j] && graph.edges[i][j] == 1) {
                DFS(graph, j, flag);
            }
        }
    }

    static void DFSTraverse(GraphMatrix graph) {
        boolean[] flag = new boolean[graph.getVertexNum()];
        for (int i = 0; i < graph.getVertexNum(); i++) {
            if (!flag[i]) {// 当前顶点没有被访问
                DFS(graph, i, flag);
            }
        }
    }

    /**
     * DFS非递归
     *
     * @param graph
     */
    static void DFS_Map(GraphMatrix graph) {
        boolean[] flag = new boolean[graph.getVertexNum()];
        LinkedList<Integer> stack = new LinkedList<>();
        for (int i = 0; i < graph.getVertexNum(); i++) {
            if (!flag[i]) {
                flag[i] = true;
                System.out.print(graph.vertexList.get(i) + " ");
                stack.push(i);
            }
            while (!stack.isEmpty()) {
                int k = stack.pop();
                for (int j = 0; j < graph.getVertexNum(); j++) {
                    if (graph.edges[k][j] == 1 && !flag[j]) {
                        flag[j] = true;
                        System.out.print(graph.vertexList.get(j) + " ");
                        stack.push(j);
                        break;
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        GraphMatrix<String> graph = new GraphMatrix<>("ABCDEFGHI");
        graph.addEdge("A", "B");
        graph.addEdge("A", "F");
        graph.addEdge("A", "G");
        graph.addEdge("B", "C");
        graph.addEdge("B", "G");
        graph.addEdge("B", "I");
        graph.addEdge("C", "D");
        graph.addEdge("C", "I");
        graph.addEdge("D", "E");
        graph.addEdge("D", "G");
        graph.addEdge("D", "H");
        graph.addEdge("D", "I");
        graph.addEdge("E", "F");
        graph.addEdge("E", "H");
        graph.addEdge("F", "G");
        graph.addEdge("G", "H");
        graph.information();
        System.out.println("DFS递归:");
        DFSTraverse(graph);
        System.out.println("\nDFS非递归:");
        DFS_Map(graph);
        System.out.println("\nBFS非递归:");
        BFSTraverse(graph);
    }
}
